package com.hjy.backend.versionManager;

import com.hjy.backend.transactionManager.TransactionManager;

/**
 * 版本的可见性工具类
 */
public class Visibility {

    /**
     * 如果 Ti 需要修改 X，而 X 已经被 Ti 不可见的事务 Tj 修改了，那么要求 Ti 回滚。
     *
     * @param tm
     * @param t
     * @param e
     * @return
     */
    public static boolean isVersionSkip(TransactionManager tm, Transaction t, Entry e) {
        long xmax = e.getXmax();
        if (t.level == 0) {
            // 读操作可以是版本跳跃的
            return false;
        } else {
            // xmax对应的事务相对于 t 是不可见的(xmax已经提交且xmax事务在t之后或者相对于t是活跃事务)
            return tm.isCommitted(xmax) && (xmax > t.xid || t.isInSnapshot(xmax));
        }
    }

    /**
     * 该记录相对于该事务是否是否可见
     *
     * @param tm
     * @param t
     * @param e
     * @return
     */
    public static boolean isVisible(TransactionManager tm, Transaction t, Entry e) {
        if (t.level == 0) {
            return readCommitted(tm, t, e);
        } else {
            return repeatableRead(tm, t, e);
        }
    }

    /**
     * `读提交` 是否允许(版本对事务的可见性逻辑如下)
     * 两种可建的情况
     * <p>
     * (XMIN == Ti and                             // 由Ti创建且
     * XMAX == NULL                            // 还未被删除
     * )
     * <p>
     * <p>
     * (XMIN is committed and                       // 由一个已提交的事务创建且
     * (XMAX == NULL or                        // 尚未删除或
     * (XMAX != Ti and XMAX is not committed)   // 由一个未提交的事务删除
     * ))
     *
     * @param tm
     * @param t
     * @param e
     * @return
     */
    private static boolean readCommitted(TransactionManager tm, Transaction t, Entry e) {
        long xid = t.xid;
        long xmin = e.getXmin();
        long xmax = e.getXmax();
        if (xmin == xid && xmax == 0) return true;

        if (tm.isCommitted(xmin)) {
            if (xmax == 0) return true;
            if (xmax != xid) {
                if (!tm.isCommitted(xmax)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * `可重复读` 是否允许
     * 当前活跃的所有事务 SP(Ti)
     * <p>
     * (XMIN == Ti and                 // 由Ti创建且
     * (XMAX == NULL or               // 尚未被删除
     * ))
     * or                              // 或
     * (XMIN is committed and           // 由一个已提交的事务创建且
     * XMIN < XID and                 // 这个事务小于Ti且
     * XMIN is not in SP(Ti) and      // 这个事务在Ti开始前提交且
     * (XMAX == NULL or               // 尚未被删除或
     * (XMAX != Ti and               // 由其他事务删除但是
     * (XMAX is not committed or     // 这个事务尚未提交或
     * XMAX > Ti or                    // 这个事务在Ti开始之后才开始或
     * XMAX is in SP(Ti)               // 这个事务在Ti开始前还未提交
     * ))))
     *
     * @param tm
     * @param t
     * @param e
     * @return
     */
    private static boolean repeatableRead(TransactionManager tm, Transaction t, Entry e) {
        long xid = t.xid;
        long xmin = e.getXmin();
        long xmax = e.getXmax();
        if (xmin == xid && xmax == 0) return true;

        if (tm.isCommitted(xmin) && xmin < xid && !t.isInSnapshot(xmin)) {
            if (xmax == 0) return true;
            if (xmax != xid) {
                if (!tm.isCommitted(xmax) || xmax > xid || t.isInSnapshot(xmax)) {
                    return true;
                }
            }
        }
        return false;
    }

}
